#include "stdfFile.h"

#include <iostream>
#include <map>
#include <vector>

#include "utility.h"

namespace stdf {

    StdfFile::StdfFile() {
    }

    StdfFile::StdfFile(string name, RWMode mode)
        : fileName(name), rwMode(mode), stdfStream( name, mode)
    {

    }

    bool StdfFile::open(string name, RWMode mode) {
        bool result = false;

        result = stdfStream.open( name, mode);

        if(result == true) {
            fileName = name;
            rwMode   = mode;
        }

        return result;
    }

    bool StdfFile::read(vector< vector<string> >& data, vector< vector<string> >& headerData) {
        bool result = true;

        RecordHeader header;
        FARRecord far;
        MIRRecord mir;
        // Keep a vec/list of all header records
        std::vector<ATRRecord> atrVec;
        std::vector<SDRRecord> sdrVec;
        std::vector<PLRRecord> plrVec;
        std::vector<PGRRecord> pgrVec;
        std::vector<PMRRecord> pmrVec;

        //
        // Local flags
        //
        bool validRecord = true;
        bool foundMIR = false;
        bool foundPIR = false;
        bool foundSummary = false;


        // Read FAR and set byte order
        //stdfStream >> header;
        //stdfStream >> far;
        stdfStream.readRecordHeader(header);
        stdfStream.readRecord(far);
        stdfStream.setByteOrder(far.getByteOrder());
        //std::cout << header << std::endl;
        std::cout << far << std::endl;

        if(far.stdfVersion == 3)
            return false;

        //
        // Now that stdf file has been opened, it is ok to clear the data container
        //
        data.clear();

        vector< string > columnHeader;
        map< U4, std::pair<unsigned int, string> > testNum2index;
        map< U4, std::pair<unsigned int, string> >::iterator iterMap;
        vector< vector<string> > touchDownTestResults, touchDownPartInfo;
        unsigned int uniqueTestCount = 0;

        while(stdfStream.is_open() && stdfStream.good() && (!stdfStream.eof())) {
            stdfStream.readRecordHeader(header);
            std::cout << header << std::endl;
            RecordType recType = header.getRecordType();

            if(recType == PIR) foundPIR     = true;
            if(recType == TSR) foundSummary = true;

            int recReadLen = 0;
            if(foundMIR == false) {
                // Initial set of valid records are ATR, MIR
                if(recType == ATR) {
                    ATRRecord atr;
                    recReadLen = stdfStream.readRecord(atr);
                    atrVec.push_back(atr);
                }
                else if(recType == MIR) {
                    recReadLen = stdfStream.readRecord(mir);
                    std::cout << mir << std::endl;
                    foundMIR = true;
                }
                else {
                    // TODO: Error out and exit
                    // For now just skip
                    validRecord = false;
                    //recReadLen = stdfStream.skip(header.getLength());
                }
            }
            else if((foundMIR == true) && (foundPIR == false)) {
                // Now the valid records are SDR, PLR, PGR, PMR
                if(recType == SDR) {
                    SDRRecord sdr;
                    recReadLen = stdfStream.readRecord(sdr);
                    std::cout << sdr << std::endl;
                }
                else if(recType == PMR) {
                    PMRRecord pmr;
                    recReadLen = stdfStream.readRecord(pmr);
                    std::cout << pmr << std::endl;
                }
                else if(recType == PLR) {
                    // PLR record is not very useful
                    PLRRecord plr;
                    recReadLen = stdfStream.readRecord(plr);
                    std::cout << plr << std::endl;
                }
                else if(recType == PGR) {
                    PGRRecord pgr;
                    recReadLen = stdfStream.readRecord(pgr);
                    std::cout << pgr << std::endl;
                }
                else {
                    // TODO: Error out and exit
                    validRecord = false;
                    //recReadLen = stdfStream.skip(header.getLength());
                }
            }
            else if((foundMIR == true) && (foundPIR == true) && (foundSummary == false)) {
                if(recType == PIR) {
                    PIRRecord pir;
                    recReadLen = stdfStream.readRecord(pir);
                    std::cout << pir << std::endl;
                }
                else if(recType == PTR) {
                    PTRRecord ptr;
                    recReadLen = stdfStream.readRecord(ptr);
                    std::cout << ptr << std::endl;
                    iterMap = testNum2index.find(ptr.testNumber);
                    // If this is the first time we encounter this test then add it to the map
                    if(iterMap == testNum2index.end()) {
                        testNum2index[ptr.testNumber] = std::make_pair( uniqueTestCount, ptr.testText.str());
                        uniqueTestCount++;
                    }

                    if(ptr.considerResult()) {
                        if(touchDownTestResults.size() < ptr.siteNumber) {
                            touchDownTestResults.resize( ptr.siteNumber);
                        }

                        unsigned int testIndex = testNum2index[ptr.testNumber].first;
                        if( touchDownTestResults[ptr.siteNumber - 1].size() <= testIndex)
                            touchDownTestResults[ptr.siteNumber - 1].resize(testIndex + 1);

                        std::cout << "Sites : " << touchDownTestResults.size() << " Site 1 size : " << touchDownTestResults[0].size() << endl;

                        touchDownTestResults[ptr.siteNumber - 1][testIndex] = toString(ptr.testResult);
                    }
                }
                else if(recType == PRR) {
                    PRRRecord prr;
                    recReadLen = stdfStream.readRecord(prr);
                    std::cout << prr << std::endl;

                    if(prr.siteNumber > 0 && prr.siteNumber < 255) {
                        data.push_back(touchDownTestResults[prr.siteNumber - 1]);
                        touchDownTestResults[prr.siteNumber - 1].clear();
                    }
                }
                else {
                    // TODO: Error out and exit
                    validRecord = false;
                    //recReadLen = stdfStream.skip(header.getLength());
                }
            }
            else if(foundSummary == true) {
                if(recType == TSR) {
                    TSRRecord tsr;
                    recReadLen = stdfStream.readRecord(tsr);
                    std::cout << tsr << std::endl;
                }
                else if(recType == WCR) {
                    WCRRecord wcr;
                    recReadLen = stdfStream.readRecord(wcr);
                    std::cout << wcr << std::endl;
                }
                else if(recType == HBR) {
                    HBRRecord hbr;
                    recReadLen = stdfStream.readRecord(hbr);
                    std::cout << hbr << std::endl;
                }
                else if(recType == SBR) {
                    SBRRecord sbr;
                    recReadLen = stdfStream.readRecord(sbr);
                    std::cout << sbr << std::endl;
                }
                else if(recType == PCR) {
                    PCRRecord pcr;
                    recReadLen = stdfStream.readRecord(pcr);
                    std::cout << pcr << std::endl;
                }
                else if(recType == MRR) {
                    MRRRecord mrr;
                    recReadLen = stdfStream.readRecord(mrr);
                    std::cout << mrr << std::endl;
                }
                else
                    validRecord = false;
            }
            else {
                validRecord = false;
            }

            if(recReadLen < header.getLength()) {
                std::cerr << "Invalid record length" << std::endl;
            }
            if(validRecord == false) {
                // TODO: Error out and exit
                U2 len = header.getLength();
                recReadLen = stdfStream.skip(len);
                validRecord = true;
                result = false;
            }
            std::cout << "Record Read Length : " << recReadLen << std::endl;

            stdfStream.peek(); // Need this so that the eof flag can be set
        }


        for(iterMap = testNum2index.begin(); iterMap != testNum2index.end(); iterMap++) {
            unsigned int index = (*iterMap).second.first;
            string       name  = (*iterMap).second.second;
            if(columnHeader.size() <= index)
                columnHeader.resize(index + 1);
            columnHeader[index] = name;
        }

        headerData.push_back(columnHeader);

        return result;
    }

} // end namespace
